using System;
using System.Collections.Generic;
using System.Text;
using TTXNA.src.Util;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using TTXNA.src.Engine.Graphics;
using TTXNA.src.Engine.Create.Tools;

namespace TTXNA.src.Engine.Input
{
    public class InputHandler : TTUpdateable
    {
        private TTXNAGame game;
        private Toolbox toolbox;

        private TTInput gameInput;
        private MouseState onRMB;

        public InputHandler(TTXNAGame game)
        {
            this.game = game;
            gameInput = new TTInput();
            toolbox = new Toolbox(game);
            toolbox.ChangeToolStatus(ToolType.Landscaping, true);
        }

        public void Update(GameTime gameTime)
        {
            gameInput.Update(gameTime);

            HandleKeyboard(gameTime);
            HandleMouse(gameTime);
            //GUI
            //WORLD PICKING
        }


        private void HandleKeyboard(GameTime gameTime)
        {
            KeyboardState oldState = gameInput.Keyboard.OldState;
            KeyboardState newState = gameInput.Keyboard.NewState;

            if (newState.IsKeyDown(Keys.R) && oldState.IsKeyUp(Keys.R))
               (toolbox.GetTool(ToolType.Landscaping) as LandscapingTool).ActiveTool = LandscapingType.Raise;

           if (newState.IsKeyDown(Keys.L) && oldState.IsKeyUp(Keys.L))
               (toolbox.GetTool(ToolType.Landscaping) as LandscapingTool).ActiveTool = LandscapingType.Lower;
        }

        private void HandleMouse(GameTime gameTime)
        {
            MouseState oldState = gameInput.Mouse.OldState;
            MouseState newState = gameInput.Mouse.NewState;

            MouseData data = new MouseData();
            data.CursorLocation = new Point(newState.X - oldState.X, newState.Y - oldState.Y);
            data.LeftMouseButtonDown = (newState.LeftButton == ButtonState.Pressed);
            data.RightMouseButtonDown = (newState.RightButton == ButtonState.Pressed);
            data.MiddleMouseButtonDown = (newState.MiddleButton == ButtonState.Pressed);
            data.ScrollWheelDelta = newState.ScrollWheelValue - oldState.ScrollWheelValue;

            bool onGUI = UpdateGUI(data, gameTime);

            if (!onGUI)
            {
                UpdateCamera(gameTime);

                GridPickData gpd = HandlePicking(gameTime);
                HandleToolbox(gpd);
            }
        }

        private void HandleToolbox(GridPickData gpd)
        {
            Point mouseLoc = new Point(gameInput.Mouse.NewState.X, gameInput.Mouse.NewState.Y);

            toolbox.MouseMove(mouseLoc, gpd);

            if (gameInput.Mouse.NewState.LeftButton == ButtonState.Pressed)
                toolbox.MouseDown(mouseLoc, gpd);
            else
                toolbox.MouseUp(mouseLoc, gpd);

        }

        private GridPickData HandlePicking(GameTime gameTime)
        {
            Vector2 mouseLoc = new Vector2(gameInput.Mouse.NewState.X, gameInput.Mouse.NewState.Y);

            if (TTXNAGame.graphicsWorld.TerrainMesh != null)
            {
                Ray rayDir = CalculateCursorRay(mouseLoc, game.Camera.Projection, game.Camera.View);
                return TTXNAGame.graphicsWorld.TerrainMesh.Pick(rayDir);
            }

            return new GridPickData(Coordinate.Invalid, Coordinate.Invalid, RotateType.Invalid);
        }

        public Ray CalculateCursorRay(Vector2 position, Matrix projectionMatrix, Matrix viewMatrix)
        {
            Vector3 nearSource = new Vector3(position, 0f);
            Vector3 farSource = new Vector3(position, 1f);

            Vector3 nearPoint = game.GraphicsDevice.Viewport.Unproject(nearSource,
                projectionMatrix, viewMatrix, Matrix.Identity);

            Vector3 farPoint = game.GraphicsDevice.Viewport.Unproject(farSource,
                projectionMatrix, viewMatrix, Matrix.Identity);

            Vector3 direction = farPoint - nearPoint;
            direction.Normalize();

            return new Ray(nearPoint, direction);
        }

        private bool UpdateGUI(MouseData data, GameTime gameTime)
        {
            return game.GUI.MouseHandler(data);
        }

        private void UpdateCamera(GameTime gameTime)
        {
            MouseState newState = gameInput.Mouse.NewState;
            MouseState lastState = gameInput.Mouse.OldState;

            TTCamera camera = game.Camera;

            if (newState.RightButton == ButtonState.Pressed)
            {
                game.IsMouseVisible = false;

                if (lastState.RightButton == ButtonState.Released)
                {
                    onRMB = newState;
                }
                else
                {
                    int xChange = newState.X - onRMB.X;
                    int yChange = newState.Y - onRMB.Y;

                    camera.AdjustYaw((float)xChange);
                    camera.AdjustPitch((float)yChange);

                    Mouse.SetPosition(onRMB.X, onRMB.Y);
                }
            }
            else
            {
                game.IsMouseVisible = true;
            }

            camera.MoveForward(GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y * 3);
            camera.Strafe(GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X * 3);
            camera.AdjustYaw(GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X);
            camera.AdjustPitch(-GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y);
            camera.UpDown(GamePad.GetState(PlayerIndex.One).Triggers.Right);
            camera.UpDown(-GamePad.GetState(PlayerIndex.One).Triggers.Left);

            KeyboardState kb = Keyboard.GetState();

            if (kb.IsKeyDown(Keys.W))
                camera.MoveForward(5);
            if (kb.IsKeyDown(Keys.S))
                camera.MoveForward(-5);
            if (kb.IsKeyDown(Keys.A))
                camera.Strafe(-5);
            if (kb.IsKeyDown(Keys.D))
                camera.Strafe(5);
            if (kb.IsKeyDown(Keys.Q))
                camera.UpDown(5);
            if (kb.IsKeyDown(Keys.Z))
                camera.UpDown(-5);


            camera.Update(gameTime);
        }

    }
}
